/*--------------------------------------------------------
Copyright (c) 2010 Apolo Pena

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------*/
package org.flashalchemy.ezlib.ezlog.data
{
    import org.flashalchemy.ezlib.ezlog.events.EZLogDataXmlParserEvent;
    import org.flashalchemy.ezlib.ezlog.targets.EzTraceTarget;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import mx.logging.ILogger;
    import mx.logging.Log;


    /**
     * <b>Description:</b>The <code>EzLogDataXmlParser</code> is an object used to validate and parse an EzLogData.xml file.<p/>
     * <b>Usage:</b><br>
     * <pre>
     * 		var parser:EzLogDataXmlParser = new EzLogDataXmlParser();
     *      parser.addEventListener(EzLogDataXmlParserEvent.PARSE_COMPLETE, onEzLogDataXmlParseComplete, false, 0, true);
     *      parser.initialize((xmlFilePath));
     * </pre>
     * @see org.flashalchemy.ezlib.logging.data.EzLogDataValidator
     */
    public class EzLogDataXmlParser extends EventDispatcher
    {
        /**
         * Use this variable to check to see if this object has been initialized.
         * @return Flag indicating if this objected has been initialized previously
         */
        public function get isInited():Boolean
        {
            return _isInited;
        }

        /**
         * @private
         * initialization flag
         **/
        private var _isInited:Boolean = false;

        /**
         * @private
         * Standard Flex Logger, used to report warnings and errors regarding this class
         */
        private var logger:ILogger;

        /**
         * Constructor just calls super()
         */
        public function EzLogDataXmlParser()
        {
            super();
        }

        /**
         * @private
         * The xml object loaded in
         **/
        private var _xml:XML;

        /**
         * @private
         * The path to the xml file to be loaded, this is set via the constructor
         **/
        private var _path:String;

        /**
         * @private
         * The URLLoader object to load the xml file
         **/
        private var _xmlLoader:URLLoader;

        /**
         * The parsed data which is an array of <code>EzLogData</code> objects.
         * An empty array will be returned if the data has not yet been parsed
         * @return
         */
        public function get payload():Array
        {
            return _payload;
        }

        /**
         * @private
         * The parsed data from the xml file which will be An Array of validated EzLogData objects
         **/
        private var _payload:Array = new Array();

        /**
         * Starts the chain of events. Loads the xml file represented by the path parameter whihc is then parsed and returns
         * the parsed data through a <code>EzLogDataXmlParserEvent.PARSE_COMPLETE</code> event.. This method can only be
         * called once, no action will be taken on all calls made past the first call.
         * @param path The Ez Log Data XML file to load and parse
         */
        public function initialize(path:String):void
        {
            if (!_isInited)
            {
                var tt:EzTraceTarget = new EzTraceTarget();
                tt.omitPackagePathFromCategory = false;
                Log.flush();
                Log.addTarget(tt);
                logger = Log.getLogger("org.flashalchemy.ezlib.ezlog.data.EzLogDataXmlParser");
                _path = path;
                _xml = new XML();
                _xml.ignoreWhiteSpace = true;
                _xml.ignoreComments = true;
                var _xmlUrlRequest:URLRequest = new URLRequest(path);
                _xmlLoader = new URLLoader(_xmlUrlRequest);
                _xmlLoader.addEventListener(Event.COMPLETE, onXmlLoaded);
                _isInited = true;
            }
            else
            {
                logger.warn('initialize() called more than oonce, no action taken');
            }
        }

        /**
         * @private
         * Parses the loaded xml and returns the parsed data via a <code>EzLogDataXmlParserEvent.PARSE_COMPLETE</code> event.
         * The data will be an Array of <code>EzLogData</code> objects
         **/
        private function onXmlLoaded(evt:Event):void
        {
            var payload:Array = parse(XML(evt.currentTarget.data));
            var eldxpe:EZLogDataXmlParserEvent = new EZLogDataXmlParserEvent(EZLogDataXmlParserEvent.PARSE_COMPLETE, payload);
            dispatchEvent(eldxpe);
        }

        /**
         * @private
         * The parsed filter data for each log target
         **/
        private var filtersSets:Array = [];

        /**
         * @private
         * The parsed data for each log target
         **/
        private var logTargets:Array = [];

        /**
         * @protected
         * Parses the xml file loaded according to the path varaible pass into the constructor
         **/
        protected function parse(xml:XML):Array
        {
            var logTargetList:XMLList = xml.logTargets.children();
            var logTargetLength:int = logTargetList.length();
            var logTargetPayloads:Array = [];
            var filtersPayloads:Array = [];
            var logDataValidator:EzLogDataValidator = new EzLogDataValidator();
            var logData:EzLogData;
            var _return:Array = [];
            for (var i:int = 0; i < logTargetLength; i++)
            {
                var themeId:String = null;
                // now determine if there is a theme attribute set in the xml for this node and set if if needed
                xml.logTargets.logTarget[i].attribute('theme').length() < 1 ? themeId = null : themeId = xml.logTargets.logTarget[i].attribute('theme');
                var alphaString:String = xml.logTargets.logTarget[i].attribute('alpha');
                var alpha:Number;
                if (alphaString != "")
                {
                    alpha = parseFloat(alphaString);
                }
                //create the log target payload to be delivered via an event
                var logTargetPayload:EzLogTargetData = new EzLogTargetData(xml.logTargets.logTarget[i].consoleTitle.toString(), logTargetList.attribute('type')[i].toString(), logTargetList.attribute('formatting')[i].
                                                                               toString(), alpha, themeId);
                if (logDataValidator.isValidLogTargetData(logTargetPayload))
                {
                    logTargetPayloads.push(logTargetPayload);
                }
                else
                {
                    logger.error('invalid logTarget node(s) in the file: ' + _path);
                    logger.fatal('FATAL: EzLog is compromised!');
                }
                var filterNodesList:XMLList = logTargetList[i].filters.children();
                var filterTotal:int = filterNodesList.length();
                var filters:Array = [];
                for (var j:int = 0; j < filterTotal; j++)
                {
                    filters.push(filterNodesList[j].toString());
                }
                var filtersPayload:EzLogTargetFilterData = new EzLogTargetFilterData(filters, i);
                if (logDataValidator.isValidLogTargetFilterData(filtersPayload))
                {
                    filtersPayloads.push(filtersPayload);
                }
                else
                {
                    logger.warn('invalid filter node(s) in the file: ' + _path);
                    logger.error('FATAL: EzLog is compromised!');
                }
                _return.push(new EzLogData(logTargetPayloads[i], filtersPayloads[i]));
            }
            return _return;
        }
    }
}

